You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

124 lines
4.1 KiB

<script setup lang="ts">
const route = useRoute()
const id = route.params.id as string
const { data, refresh } = await useHttpFetch(`/api/scheduler/tasks/${id}`)
const task = computed(() => data.value?.task)
const recentExecutions = computed(() => data.value?.recentExecutions ?? [])
async function handleTrigger() {
await $fetch(`/api/scheduler/tasks/${id}/trigger`, { method: "POST" })
}
async function handleToggle() {
if (!task.value) return
await $fetch(`/api/scheduler/tasks/${id}/toggle`, {
method: "POST",
body: { enabled: !task.value.enabled },
})
refresh()
}
function statusColor(status: string): "success" | "error" | "warning" | "neutral" {
switch (status) {
case "success": return "success"
case "failed": return "error"
case "running": return "warning"
default: return "neutral"
}
}
function timeAgo(ts: number): string {
const diff = Date.now() - ts
const mins = Math.floor(diff / 60000)
if (mins < 1) return "just now"
if (mins < 60) return `${mins}m ago`
const hours = Math.floor(mins / 60)
if (hours < 24) return `${hours}h ago`
return `${Math.floor(hours / 24)}d ago`
}
</script>
<template>
<div class="p-6 max-w-4xl mx-auto">
<div class="mb-4">
<ULink to="/admin/scheduler" class="text-sm text-gray-500">&larr; Back to tasks</ULink>
</div>
<div v-if="task" class="space-y-6">
<!-- Task header -->
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold">{{ task.name }}</h1>
<p class="text-sm text-gray-500 mt-1">
{{ task.cronExpression }} &middot; {{ task.type }}
</p>
</div>
<div class="flex gap-2">
<UButton variant="outline" @click="handleTrigger">Trigger Now</UButton>
<UButton variant="outline" @click="handleToggle">
{{ task.enabled ? 'Pause' : 'Resume' }}
</UButton>
</div>
</div>
<!-- Task config -->
<div class="rounded-lg border p-4">
<h2 class="font-semibold mb-3">Configuration</h2>
<dl class="grid grid-cols-2 gap-2 text-sm">
<dt class="text-gray-500">Type</dt>
<dd>{{ task.type }}</dd>
<template v-if="task.type === 'function'">
<dt class="text-gray-500">Function</dt>
<dd>{{ task.functionName }}</dd>
<dt class="text-gray-500">Payload</dt>
<dd><code>{{ task.functionPayload }}</code></dd>
</template>
<template v-if="task.type === 'http'">
<dt class="text-gray-500">Method</dt>
<dd>{{ task.httpMethod }}</dd>
<dt class="text-gray-500">URL</dt>
<dd>{{ task.httpUrl }}</dd>
</template>
<dt class="text-gray-500">Catch Up</dt>
<dd>{{ task.catchUp ? 'Yes' : 'No' }}</dd>
<dt class="text-gray-500">Retries</dt>
<dd>{{ task.maxRetries }}</dd>
<dt class="text-gray-500">Timeout</dt>
<dd>{{ task.timeoutSeconds }}s</dd>
<dt class="text-gray-500">Created</dt>
<dd>{{ new Date(task.createdAt).toLocaleString() }}</dd>
</dl>
</div>
<!-- Execution history -->
<div class="rounded-lg border">
<h2 class="font-semibold p-4 border-b">Recent Executions</h2>
<div v-if="recentExecutions.length === 0" class="p-4 text-sm text-gray-400">
No executions yet
</div>
<div v-else>
<div
v-for="log in recentExecutions"
:key="log.id"
class="flex items-center gap-3 p-3 border-b last:border-b-0"
>
<UBadge :color="statusColor(log.status)" variant="subtle" size="sm">
{{ log.status }}
</UBadge>
<span class="text-sm text-gray-500 flex-1">
{{ timeAgo(log.startedAt) }}
</span>
<span v-if="log.resultSummary" class="text-sm text-gray-600">
{{ log.resultSummary }}
</span>
</div>
</div>
</div>
</div>
<div v-else-if="data" class="text-gray-400">
Task not found.
</div>
</div>
</template>